#ifndef __CRC_H__
#define __CRC_H__

#include "common.h"

typedef unsigned long uint8_least;

#define CRC_ZERO_U (0U)
#define CRC_ONE_U (1U)
#define CRC_BYTELENGTH_U (8U)
#define CRC_BITCNT_THIRTYTWO ((uint8)32U)
#define CRC_BITCNT_EIGHT ((uint8)8U)

#define CRC_CRC8_MSB ((uint8)0x80)
#define CRC_INITIAL_VALUE8 ((uint8)0xFFU)
#define CRC_INITIAL_VALUE8H2F ((uint8)0xFFU)
#define CRC_INITIAL_VALUE16 ((uint16)0xFFFFU)
#define CRC_INITIAL_VALUE32 ((uint32)0xFFFFFFFFU)
#define CRC_INITIAL_VALUE32P4 ((uint32)0xFFFFFFFFU)

#define CRC_CRC8_XOR_VALUE ((uint8)0xFFU)
#define CRC_CRC8H2F_XOR_VALUE ((uint8)0xFFU)
#define CRC_CRC16_XOR_VALUE ((uint16)0x0000U)
#define CRC_CRC16_ARC_XOR_VALUE ((uint16)0x0000U)
#define CRC_CRC32_XOR_VALUE ((uint32)0xFFFFFFFFuL)
#define CRC_CRC32P4_XOR_VALUE ((uint32)0xFFFFFFFFuL)
#define CRC_CRC16_SIZE (16U)
#define CRC_CRC16_MSB ((uint16)0x8000U)
#define CRC_CRC32_SIZE (32U)
#define CRC_CRC32_MSB ((uint32)0x80000000U)

#define CRC_CRC8_POLYNOMIAL ((uint8)0x1DU)
#define CRC_CRC8H2F_POLYNOMIAL ((uint8)0x2FU)
#define CRC_CRC16_POLYNOMIAL ((uint16)0x1021U)
#define CRC_CRC32_POLYNOMIAL ((uint32)0x04C11DB7U)
#define CRC_CRC32P4_POLYNOMIAL ((uint32)0xF4ACFB13U)

#define CRC_U16LSB_MASK ((uint32)0xFFU)
#define CRC_U32LSB_MASK ((uint32)0xFFU)

#define CRC_SHIFT_TWENTYFOUR ((uint32)24U)

#define CRC_TABLE_LENGTH ((uint32)256U)

#define CRC_RUNTIME_MODE (0x01u)
#define CRC_TABLE_MODE (0x02u)

#if 1
#define CRC_8_MODE CRC_RUNTIME_MODE
#define CRC_8H2F_MODE CRC_RUNTIME_MODE
#define CRC_16_MODE CRC_RUNTIME_MODE
#define CRC_32_MODE CRC_RUNTIME_MODE
#define CRC_32P4_MODE CRC_RUNTIME_MODE
#else
#define CRC_8_MODE CRC_TABLE_MODE
#define CRC_8H2F_MODE CRC_TABLE_MODE
#define CRC_16_MODE CRC_TABLE_MODE
#define CRC_32_MODE CRC_TABLE_MODE
#define CRC_32P4_MODE CRC_TABLE_MODE
#endif

uint8 Crc_CalculateCRC8(const uint8 *const Crc_DataPtr, const uint32 Crc_Length,
                        const uint8 Crc_StartValue8,
                        const boolean Crc_IsFirstCall);
uint8 Crc_CalculateCRC8H2F(const uint8 *const Crc_DataPtr,
                           const uint32 Crc_Length,
                           const uint8 Crc_StartValue8H2F,
                           const boolean Crc_IsFirstCall);
uint16 Crc_CalculateCRC16(const uint8 *const Crc_DataPtr,
                          const uint32 Crc_Length,
                          const uint16 Crc_StartValue16,
                          const boolean Crc_IsFirstCall);

uint32 Crc_CalculateCRC32(const uint8 *const Crc_DataPtr,
                          const uint32 Crc_Length,
                          const uint32 Crc_StartValue32,
                          const boolean Crc_IsFirstCall);
uint32 Crc_CalculateCRC32P4(const uint8 *const Crc_DataPtr,
                            const uint32 Crc_Length,
                            const uint32 Crc_StartValue32,
                            const boolean Crc_IsFirstCall);

#endif